package com.pipayshop.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pipayshop.config.OrderQueueConfig;
import com.pipayshop.entity.HotelShopInfo;
import com.pipayshop.entity.HotelStoreOrderInfo;
import com.pipayshop.entity.TransactionRecord;
import com.pipayshop.entity.vo.*;
import com.pipayshop.exception.BusinessException;
import com.pipayshop.mapper.*;
import com.pipayshop.service.HotelShopOrderInfoService;
import com.pipayshop.utils.Constants;
import com.pipayshop.utils.StringUtil;
import com.pipayshop.utils.TokenUtil;
import com.pipayshop.utils.ValidationUtil;
import io.jsonwebtoken.Claims;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.modelmapper.ModelMapper;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;


/**
 * @author wzx
 */
@Service
public class HotelShopOrderInfoServiceImpl extends ServiceImpl<HotelShopOrderInfoMapper, HotelStoreOrderInfo> implements HotelShopOrderInfoService {

    @Resource
    HotelShopOrderInfoMapper shopOrderInfoMapper;
    @Resource
    HotelTransactionRecordMapper hotelTransactionRecordMapper;
    @Resource
    @Qualifier("hotelAccountInfoMapper")
    HotelAccountInfoMapper hotelAccountInfoMapper;

    @Resource
    HotelShopCommodityInfoMapper shopCommodityInfoMapper;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private HotelShopCommodityLiveInfoMapper shopCommodityLiveInfoMapper;

    @Autowired
    HotelShopInfoMapper hotelShopInfoMapper;


    @Override
    @Cacheable(value = Constants.PHYSICAL_LIVE_ORDER_LIST_KEY)
    public List<LiveOrderListVO> getOrderList(GetLiveOrderDataVO getOrderDataVO) {
        // 校验 currentPage 和 pageSize
        Long start = getOrderDataVO.getCurrentPage();
        Long size = getOrderDataVO.getPageSize();

        if (start == null || start < 1) {
            start = 1L;
        }
        if (size == null || size < 1) {
            size = 10L;
        }
        // 校验 userId 和 shopId
        String userId = getOrderDataVO.getUserId();
        ValidationUtil.validateString(userId, "user_id_required");
        // 校验 orderStatus
        List<Integer> orderStatus = getOrderDataVO.getOrderStatus();

        // 分页计算
        start = (start - 1) * size;

        return shopOrderInfoMapper.getOrderList(userId, start, size, orderStatus);
    }


    @Override
    public List<LiveOrderListVO> getLiveOrderListByShopName(GetLiveOrderByNameVO getLiveOrderByNameVO) {
        String userId = getLiveOrderByNameVO.getUserId();
        ValidationUtil.validateString(userId, "user_id_required");
        String commodityName = getLiveOrderByNameVO.getCommodityName();
        ValidationUtil.validateString(commodityName, "commodity_name_required");
        List<Integer> orderStatus = getLiveOrderByNameVO.getOrderStatus();
        return shopOrderInfoMapper.getLiveOrderListByShopName(userId, orderStatus, commodityName);
    }


    @Override
    public PageDataVO getOrderLiveList(GetOrderDataVO getOrderDataVO) {
        String userId = getOrderDataVO.getUserId();
        ValidationUtil.validateString(userId, "user_id_required");
        Integer start = getOrderDataVO.getCurrentPage();
        ValidationUtil.validatePositiveNumber(start, "page_number_invalid");

        Integer size = getOrderDataVO.getPageSize();
        ValidationUtil.validatePositiveNumber(size, "page_size_invalid");

        getOrderDataVO.setCurrentPage((start - 1) * size);
        Integer allOrderLiveList = shopOrderInfoMapper.getAllOrderLiveList(getOrderDataVO);
        List<OrderLiveListVO> orderLiveList = shopOrderInfoMapper.getOrderLiveList(getOrderDataVO);
        List<OrderLiveListVO2> orderLiveList2 = new ArrayList<>();

        for (OrderLiveListVO o1 : orderLiveList) {
            ModelMapper modelMapper = new ModelMapper();
            OrderLiveListVO2 o2 = modelMapper.map(o1, OrderLiveListVO2.class);
            if (o1.getImageList() != null) {
                JSONArray imageArray = JSON.parseArray(o1.getImageList());
                List<String> imageList = JSON.parseArray(imageArray.toJSONString(), String.class);
                o2.setImageList(imageList);
            }
            orderLiveList2.add(o2);
        }
        return new PageDataVO(allOrderLiveList, orderLiveList2);
    }

    @Override
    @CacheEvict(value = Constants.PHYSICAL_LIVE_ORDER_LIST_KEY, allEntries = true)
    public int delOrderByOrderId(String orderId) {
        if (StringUtils.isEmpty(orderId)) {
            return 0;
        }

        return shopOrderInfoMapper.update(null, new UpdateWrapper<HotelStoreOrderInfo>()
                .eq("order_id", orderId)
                .set("del_flag", 1)
                .set("update_time", new Date()));
    }

    @Override
    public ShopOrderDetailVO getOrderDetail(String orderId) {
        return shopOrderInfoMapper.getShopOrderDetailVO(orderId);
    }


    @Override
    @CacheEvict(value = Constants.PHYSICAL_LIVE_ORDER_LIST_KEY, allEntries = true)
    public int completedOrder(String orderId) {
        if (StringUtils.isEmpty(orderId)) {
            return 0;
        }
        return shopOrderInfoMapper.update(null, new UpdateWrapper<HotelStoreOrderInfo>()
                .eq("order_id", orderId)
                .set("order_status", 2)
                .set("update_time", new Date()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = Constants.PHYSICAL_LIVE_ORDER_LIST_KEY, allEntries = true)
    public int failOrder(String orderId) {
        if (StringUtils.isEmpty(orderId)) {
            return 0;
        }
        HotelStoreOrderInfo one = shopOrderInfoMapper.selectOne(new LambdaQueryWrapper<HotelStoreOrderInfo>()
                .eq(HotelStoreOrderInfo::getOrderId, orderId)
                .eq(HotelStoreOrderInfo::getDelFlag, 0)
                .eq(HotelStoreOrderInfo::getOrderStatus, 0));
        if (one == null) {
            return 0;
        }
        int i = shopCommodityInfoMapper.addStock(one.getNumber(), one.getCommodityId());
        int i1 = shopOrderInfoMapper.update(null, new UpdateWrapper<HotelStoreOrderInfo>()
                .eq("order_id", orderId)
                .set("order_status", 3)
                .set("update_time", new Date()));
        if (i < 1 || i1 < 1) {
            throw new BusinessException("order_update_failed");
        }
        return 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = Constants.PHYSICAL_LIVE_ORDER_LIST_KEY, allEntries = true)
    public int failLiveOrder(String orderId) {
        if (StringUtils.isEmpty(orderId)) {
            return 0;
        }
        HotelStoreOrderInfo one = shopOrderInfoMapper.selectOne(new LambdaQueryWrapper<HotelStoreOrderInfo>()
                .eq(HotelStoreOrderInfo::getOrderId, orderId)
                .eq(HotelStoreOrderInfo::getDelFlag, 0)
                .eq(HotelStoreOrderInfo::getOrderStatus, 0));
        if (one == null) {
            return 0;
        }
        int i = shopCommodityLiveInfoMapper.addLiveStock(one.getNumber(), one.getCommodityId());
        int i1 = shopOrderInfoMapper.update(null, new UpdateWrapper<HotelStoreOrderInfo>()
                .eq("order_id", orderId)
                .set("order_status", 3)
                .set("update_time", new Date()));
        if (i < 1 || i1 < 1) {
            throw new BusinessException("order_update_failed");
        }

        return 1;
    }

    @Override
    @CacheEvict(value = Constants.PHYSICAL_LIVE_ORDER_LIST_KEY, allEntries = true)
    public void deleteFailOrders() {
        shopOrderInfoMapper.update(null, new UpdateWrapper<HotelStoreOrderInfo>()
                .eq("order_status", 3)
                .set("del_flag", 1)
                .set("update_time", new Date()));
    }


    /**
     * 生成酒店未支付订单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = Constants.PHYSICAL_LIVE_ORDER_LIST_KEY, allEntries = true)
    public String generateUnpaidLiveOrder(String token) {
        // 解析令牌
        Claims dataFromToken = TokenUtil.getDataFromToken(token);
        BigDecimal transactionAmount = BigDecimal.valueOf(Double.parseDouble(dataFromToken.get("transactionAmount", String.class)));
        String commodityId = dataFromToken.get("commodityId", String.class);
        String uid = dataFromToken.get("uid", String.class);
        String shopId = dataFromToken.get("shopId", String.class);
        Integer number = dataFromToken.get("number", Integer.class);
        // 校验 transactionAmount
        String transactionAmountStr = dataFromToken.get("transactionAmount", String.class);
        ValidationUtil.validateString(transactionAmountStr, "transaction_amount_required");

        ValidationUtil.validatePositiveBigDecimal(transactionAmount, "transaction_amount_must_be_positive");

        ValidationUtil.validateString(commodityId, "commodity_id_required");

        ValidationUtil.validateString(uid, "user_id_required");

        ValidationUtil.validatePositiveNumber(number, "commodity_quantity_invalid");

        // 生成orderId
        String orderId = StringUtil.generateShortId();
        HotelStoreOrderInfo info = new HotelStoreOrderInfo(orderId, transactionAmount, commodityId, uid, shopId, number);
        //库存递减
        int reduce = shopCommodityLiveInfoMapper.reduceLiveStock(number, commodityId);
        int insert = shopOrderInfoMapper.insert(info);

        if (insert < 1 || reduce < 1) {
            String message = "unpaid_order_generation_failed";
            throw new BusinessException(message);
        }
        // 订单十分钟未支付的失效处理
        rabbitTemplate.convertAndSend(OrderQueueConfig.HOTEL_ORDER_EXCHANGE, "hotel", "shopLive_" + orderId,
                message -> {
                    message.getMessageProperties().setExpiration("600000");
                    return message;
                });
        return orderId;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = Constants.PHYSICAL_LIVE_ORDER_LIST_KEY, allEntries = true)
    public Map<String, String> payLiveOrder(String token) {
        Claims dataFromToken = TokenUtil.getDataFromToken(token);
        String orderId = dataFromToken.get("orderId", String.class);
        String uid1 = dataFromToken.get("uid", String.class);
        BigDecimal transactionAmount = BigDecimal.valueOf(Double.parseDouble(dataFromToken.get("transactionAmount", String.class)));
        String commodityId = dataFromToken.get("commodityId", String.class);
        Integer number = dataFromToken.get("number", Integer.class);
        ValidationUtil.validateString(orderId, "order_id_required");
        ValidationUtil.validateString(uid1, "user_id_required");
        ValidationUtil.validatePositiveBigDecimal(transactionAmount, "transaction_amount_must_be_positive");
        ValidationUtil.validateString(commodityId, "commodity_id_required");
        ValidationUtil.validatePositiveNumber(number, "commodity_quantity_invalid");
        // 校验订单id是否已经存在，保证接口的幂等性，避免重复下单
        Long count = shopOrderInfoMapper.selectCount(new QueryWrapper<HotelStoreOrderInfo>()
                .eq("order_id", orderId)
                .eq("order_status", 1));
        if (count != 0) {
            throw new BusinessException("order_paid_duplicate");
        }
        // 用户余额更新
        int uid = hotelAccountInfoMapper.updatePointBalanceByUid(transactionAmount, uid1);
        if (uid < 1) {
            throw new BusinessException("update_failed");
        }
        // 商品库存 、 月售量更新
        if (shopCommodityLiveInfoMapper.selectCommodityCount(commodityId) == 1) {
            // 更新商品库存和销售
            int updateStore = shopCommodityLiveInfoMapper.updateResidueAndSales(commodityId, number);
            if (updateStore == 0) {
                throw new BusinessException("stock_update_failed");
            }
        } else {
            // 更新酒店库存和销售
            int updateHotel = shopCommodityLiveInfoMapper.updateHotelInventoryAndSales(commodityId, number);
            // 检查如果没有找到商品时
            if (updateHotel == 0) {
                throw new BusinessException("commodity_not_found");
            }
        }
        // 订单状态、修改时间更新
        int update1 = shopOrderInfoMapper.update(null, new UpdateWrapper<HotelStoreOrderInfo>()
                .eq("order_id", orderId)
                .set("order_status", 1)
                .set("update_time", new Date()));

        if (update1 < 1) {
            throw new BusinessException("update_failed");
        }
        //添加交易记录
        Map<String, String> map = new HashMap<>();
        map.put("flag", "true");
        map.put("order_id", orderId);
        return map;
    }

    @Override
    public List<HotelStoreOrderInfoVO> getAllOrderByShopId(String shopId) {
        List<HotelStoreOrderInfoVO> hotelStoreOrderInfoVOList = shopOrderInfoMapper.getAllOrderByShopId(shopId);
        if (hotelStoreOrderInfoVOList == null || hotelStoreOrderInfoVOList.isEmpty()) {
            return null;
        }
        return hotelStoreOrderInfoVOList;
    }

    @Override
    public boolean deleteOrderByOrderId(String orderId) {
        int i = shopOrderInfoMapper.delete(new LambdaQueryWrapper<HotelStoreOrderInfo>()
                .eq(HotelStoreOrderInfo::getOrderId, orderId));
        if (i < 1){
            return false;
        }else {
            return true;
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = Constants.PHYSICAL_LIVE_ORDER_LIST_KEY, allEntries = true)
    public int hotelTransaction(String token) {
        // 解密JWT获取数据，记录交易日志
        Claims claims = TokenUtil.getDataFromToken(token);
        String shopId = claims.get("shopId", String.class);
        String userId = claims.get("userId", String.class);
        BigDecimal transactionAmount = BigDecimal.valueOf(Double.parseDouble(claims.get("transactionAmount", String.class)));
        ValidationUtil.validateString(userId, "user_id_required");
        ValidationUtil.validatePositiveBigDecimal(transactionAmount, "transaction_amount_must_be_positive");
        //查询是否是会员店
        HotelShopInfo hotelShopInfo = hotelShopInfoMapper.selectShopAllInfo(shopId);
        int insert = 0;
        //if(hotelShopInfo.getMembership()==1){
        //    插入交易记录表
        //目前就算不是会员店都插入记录
        insert = hotelTransactionRecordMapper.insert(new TransactionRecord(null, StringUtil.generateShortId()
                , shopId, userId, transactionAmount, null, null, null));
        // }
        return insert;
    }


    //卖家的酒店所有订单展示
    @Override
    public PageDataVO getOrderLiveListByShopId(GetOrderDataVO getOrderDataVO) {
        String userId = getOrderDataVO.getUserId();
        ValidationUtil.validateString(userId, "user_id_required");
        Integer start = getOrderDataVO.getCurrentPage();
        Integer size = getOrderDataVO.getPageSize();
        ValidationUtil.validatePageParams(start, size, "page_number_invalid", "page_size_invalid");
        getOrderDataVO.setCurrentPage((start - 1) * size);
        Integer allOrderLiveListByShopId = shopOrderInfoMapper.getAllOrderLiveListByShopId(getOrderDataVO);
        List<OrderLiveListVO> orderLiveListByShopId = shopOrderInfoMapper.getOrderLiveListByShopId(getOrderDataVO);
        return new PageDataVO(allOrderLiveListByShopId, orderLiveListByShopId);
    }

    @Override
    public ShopLiveOrderDetailVO getLiveOrderDetail(String orderId) {
        ShopLiveOrderDetailVO liveOrderDetail = shopOrderInfoMapper.getLiveOrderDetail(orderId);
        return liveOrderDetail;
    }


    /**
     * 未支付订单改价接口
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = Constants.PHYSICAL_LIVE_ORDER_LIST_KEY, allEntries = true)
    public int changePrice(String token) {
        Claims dataFromToken = TokenUtil.getDataFromToken(token);
        String orderId = dataFromToken.get("orderId", String.class);
        BigDecimal price = BigDecimal.valueOf(Double.parseDouble(dataFromToken.get("price", String.class)));
        ValidationUtil.validateString(orderId, "order_id_required");

        ValidationUtil.validatePositiveBigDecimal(price, "invalid_amount");


        return shopOrderInfoMapper.update(null, new LambdaUpdateWrapper<HotelStoreOrderInfo>()
                .eq(HotelStoreOrderInfo::getOrderId, orderId)
                .eq(HotelStoreOrderInfo::getOrderStatus, 0)
                .eq(HotelStoreOrderInfo::getDelFlag, 0)
                .set(HotelStoreOrderInfo::getTransactionAmount, price));
    }


}
